home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / wil4c10.zip / BCAST.C < prev    next >
C/C++ Source or Header  |  1997-07-26  |  14KB  |  575 lines

  1. /*
  2. **  BCAST.C (email broadcast)
  3. **
  4. **  SMTP client, uses ASYNC functions.
  5. **
  6. **  Note that this program reads BCAST.INI, which contains the
  7. **  following 4 text lines:
  8. **
  9. **      SMTP=your_SMTP_server_address
  10. **      FROM=your_email_address
  11. **      RCPT=file_with_list_of_email_addresses
  12. **      MAIL=file_to_email
  13. **
  14. **  This program emails the file specified by the "MAIL=" entry
  15. **  to each email address in the file specified by the "RCPT=" entry.
  16. **
  17. **  A typical application would be to mail out a newsletter to a list
  18. **  of subscribers.
  19. */
  20.  
  21. #include <windows.h>
  22. #include <winsock.h>
  23.  
  24. #include "wil.h"
  25. #include "about.h"
  26. #include "async.h"
  27. #include "message.h"
  28. #include "paint.h"
  29. #include "readini.h"
  30. #include "str.h"
  31.  
  32. #ifdef WIN32
  33. #define USE_INS HINSTANCE
  34. #define USE_PTR PSTR
  35. #else
  36. #define USE_INS HANDLE
  37. #define USE_PTR LPSTR
  38. #endif
  39.  
  40. LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
  41.  
  42. /* globals */
  43.  
  44. HWND hMainWnd;            /* main window handle */
  45.  
  46. #define BS            8
  47. #define LF           10
  48. #define CR           13
  49. #define ESC          27
  50.  
  51. #define MAX_BUF     512
  52. #define STR_SIZE     50
  53.  
  54. #define SMTP_PORT    25
  55.  
  56. #define SMTP_BEGIN            601
  57. #define SMTP_CONN_SUCCESS     602
  58. #define SMTP_HELO_SUCCESS     603
  59. #define SMTP_FROM_SUCCESS     604
  60. #define SMTP_TO_SUCCESS       605
  61. #define SMTP_DATA_SUCCESS     606
  62. #define SMTP_SEND             607
  63.  
  64. #define SMTP_QUIT_BEGIN       701
  65. #define SMTP_QUIT_SUCCESS     702
  66. #define SMTP_QUIT_FAILURE     703
  67.  
  68. static USE_INS hInstance;
  69. static int WinWidth = 8 * NCOLS;  /* window width */
  70. static int WinHeight = 15 * NROWS;/* window height */
  71. static char Temp[MAX_BUF+8];      /* temprary buffer */
  72. static char InBuffer[MAX_BUF+1];  /* input buffer */
  73. static SOCKET Socket = 0;         /* socket */
  74. static int EchoFlag = 1;          /* echo commands of TRUE */
  75. static HCURSOR ArrowCursor;       /* arrow cursor */
  76. static HCURSOR WaitCursor;        /* hour glass cursor */
  77.  
  78. static char SmtpString[STR_SIZE] = "";  /* SMTP server */
  79. static char FromString[STR_SIZE] = "";  /* our email address */
  80. static char RcptFile[STR_SIZE] = "";    /* destination list (user@adress) */
  81. static char MailFile[STR_SIZE] = "";    /* name of file to broadcast */
  82.  
  83. /* display error message */
  84.  
  85. static void DisplayError(int Code, LPSTR Msg)
  86. {wsprintf((LPSTR)Temp,"ERROR %d: ",Code);
  87.  DisplayString((LPSTR)Temp);
  88.  if(Msg) DisplayString(Msg);
  89.  if(Code)
  90.    {wilErrorText(Code,(LPSTR)Temp,50);
  91.     DisplayLine((LPSTR)Temp);
  92.    }
  93.  /* restore arrow cursor */
  94.  SetCursor(ArrowCursor);
  95. }
  96.  
  97. /* read text line (ending with LF) from disk */
  98.  
  99. static int ReadTextLine(int Handle, LPSTR Buffer, int BufLen)
  100. {char Ch;
  101.  int  i;
  102.  int  Size = 0;
  103.  static char TextBuffer[128];
  104.  static int  TextLeft = 0;
  105.  static int  TextRight = 0;
  106.  while(1)
  107.    {/* is TextBuffer[] empty ? */
  108.     if(TextLeft>=TextRight)
  109.       {/* read from disk */
  110.        TextLeft = 0;
  111.        TextRight = _lread(Handle,(LPSTR)TextBuffer,125) - 1;
  112.        if(TextRight<0) return -1;
  113.       }
  114.     /* copy till LF or end of buffer */
  115.     for(i=TextLeft;i<=TextRight;i++)
  116.       {Ch = TextBuffer[i];
  117.        Buffer[Size++] = 0x7f & Ch;
  118.        if(Ch=='\n')
  119.          {/* found LF */
  120.           Buffer[Size] = '\0';
  121.           TextLeft = i + 1;
  122.           return Size;
  123.          }
  124.        /* is Buffer[] filled ? */
  125.        if(Size==BufLen-3)
  126.          {/* end with CR/LF */
  127.           Buffer[Size++] = '\r';
  128.           Buffer[Size++] = '\n';
  129.           Buffer[Size] = '\0';
  130.           TextLeft = i + 1;
  131.           return Size;
  132.          }
  133.       }
  134.     /* used up all of TextBuffer[] */
  135.     TextLeft = TextRight;
  136.    } /* end-while */
  137. }
  138.  
  139. /* WinMain */
  140.  
  141. #ifdef WIN32
  142. int WINAPI
  143. #else
  144. int PASCAL
  145. #endif
  146. WinMain(USE_INS hInst, USE_INS hPrevInstance,
  147.         USE_PTR szCmdLine,  int nCmdShow)
  148. {WNDCLASS  wc;
  149.  MSG msg;
  150.  BOOL Result;
  151.  if(!hPrevInstance)
  152.    {/* register main window class */
  153.     wc.style = CS_HREDRAW | CS_VREDRAW;
  154.     wc.lpfnWndProc = MainWndProc;
  155.     wc.cbClsExtra = 0;
  156.     wc.cbWndExtra = 0;
  157.     wc.hInstance = hInst;
  158.     wc.hIcon = LoadIcon(hInst, "HostIcon");
  159.     wc.hCursor = NULL;
  160.     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  161.     wc.lpszMenuName =  "HostMenu";
  162.     wc.lpszClassName = "HostWClass";
  163.     Result = RegisterClass(&wc);
  164.     if(!Result) return FALSE;
  165.    }
  166.  
  167.  /* create main window */
  168.  hInstance = hInst;
  169.  hMainWnd = CreateWindow(
  170.         "HostWClass",   "BCAST",    WS_OVERLAPPEDWINDOW,
  171.         CW_USEDEFAULT,  CW_USEDEFAULT,
  172.         WinWidth,       WinHeight,
  173.         NULL,           NULL,
  174.         hInstance,      NULL);
  175.  ShowWindow(hMainWnd, nCmdShow);
  176.  UpdateWindow(hMainWnd);
  177.  
  178.  /* window control loop */
  179.  
  180.  while(GetMessage(&msg,NULL,0,0))
  181.    {
  182.     TranslateMessage(&msg);
  183.     DispatchMessage(&msg);
  184.    }
  185.  return (msg.wParam);
  186. } /* end WinMain */
  187.  
  188. #ifdef WIN32
  189. LRESULT CALLBACK
  190. #else
  191. long FAR PASCAL
  192. #endif
  193. MainWndProc(HWND hWindow,UINT iMsg,WPARAM wParam,LPARAM lParam)
  194. {int Code;
  195.  HDC hDC;
  196.  PAINTSTRUCT ps;
  197.  LPSTR Ptr;
  198.  static int  BufSize;
  199.  static int  RcptHandle = 0;
  200.  static int  MailHandle = 0;
  201. #ifdef WIN32
  202. #else
  203.  static FARPROC lpfnAboutDlgProc;
  204. #endif
  205.  /* begin */
  206.  hMainWnd = hWindow;
  207.  switch (iMsg)
  208.     {case WM_CREATE:
  209.       /* create cursors */
  210.       ArrowCursor = LoadCursor(NULL, IDC_ARROW);
  211.       WaitCursor = LoadCursor(NULL, IDC_WAIT);
  212.       SetCursor(ArrowCursor);
  213. #ifdef WIN32
  214. #else
  215.        /* create thunk for Win16 */
  216.        lpfnAboutDlgProc = MakeProcInstance(AboutDlgProc,hInstance);
  217. #endif
  218.       /* initialize paint module */
  219.       PaintInit();
  220.       /* attach WINSOCK */
  221.       DisplayString("Attaching WINSOCK...");
  222.       Code = wilAttach();
  223.       DisplayLine("OK");
  224.       if(Code<0) DisplayError(Code,"wilAttach fails:");
  225.       else
  226.         {wsprintf((LPSTR)Temp," Description: %s", wilGetDescription() );
  227.          DisplayLine((LPSTR)Temp);
  228.          wsprintf((LPSTR)Temp," My HostName: %s", wilGetMyHostName() );
  229.          DisplayLine((LPSTR)Temp);
  230.          wsprintf((LPSTR)Temp," My HostAddr: %s", wilGetMyHostDotted(0) );
  231.          DisplayLine((LPSTR)Temp);
  232.         }
  233.       /* open BCAST.INI file */
  234.       if(!IniOpen("BCAST.INI")) break;
  235.       while(1)
  236.         {/* read next line from BCAST.INI */
  237.          if(IniRead((LPSTR)Temp)<0) break;
  238. #if 0
  239.          /* echo strings */
  240.          DisplayLine((LPSTR)Temp);
  241. #endif
  242.          /* test for all legal keywords */
  243.          IniExtract((LPSTR)Temp,"SMTP",(LPSTR)SmtpString);
  244.          IniExtract((LPSTR)Temp,"FROM",(LPSTR)FromString);
  245.          IniExtract((LPSTR)Temp,"RCPT",(LPSTR)RcptFile);
  246.          IniExtract((LPSTR)Temp,"MAIL",(LPSTR)MailFile);
  247.         }
  248.       /* verify that we have all strings read in */
  249.       if(lstrlen((LPSTR)SmtpString)==0) DisplayLine("ERROR: Missing SMTP string.");
  250.       else
  251.         {wsprintf((LPSTR)Temp,"SMTP server is '%s'", (LPSTR)SmtpString);
  252.          DisplayLine((LPSTR)Temp);
  253.         }
  254.       if(lstrlen((LPSTR)FromString)==0) DisplayLine("ERROR: Missing FROM string.");
  255.       else
  256.         {wsprintf((LPSTR)Temp,"FROM address is '%s'", (LPSTR)FromString);
  257.          DisplayLine((LPSTR)Temp);
  258.         }
  259.       if(lstrlen((LPSTR)RcptFile)==0) DisplayLine("ERROR: Missing RCPT filename.");
  260.       else
  261.         {wsprintf((LPSTR)Temp,"RCPT file is '%s'", (LPSTR)RcptFile);
  262.          DisplayLine((LPSTR)Temp);
  263.         }
  264.       if(lstrlen((LPSTR)MailFile)==0) DisplayLine("ERROR: Missing MAIL filename.");
  265.       else
  266.         {wsprintf((LPSTR)Temp,"SMTP server is '%s'", (LPSTR)MailFile);
  267.          DisplayLine((LPSTR)Temp);
  268.         }
  269.  
  270.       /* open file to send */
  271.       MailHandle = _lopen((LPSTR)MailFile,OF_READ|OF_SHARE_DENY_WRITE);
  272.       if(MailHandle<0)
  273.         {DisplayString("ERROR: Cannot open ");
  274.          DisplayLine((LPSTR)MailFile);
  275.          break;
  276.         }
  277.       /* open RCPT file */
  278.       RcptHandle = _lopen((LPSTR)RcptFile,OF_READ|OF_SHARE_DENY_WRITE);
  279.       if(RcptHandle<0)
  280.         {DisplayString("ERROR: Cannot open ");
  281.          DisplayLine((LPSTR)RcptFile);
  282.          break;
  283.         }
  284.       break;
  285.  
  286.      case WM_COMMAND:
  287.          switch(wParam)
  288.            {
  289.             case MSG_ABOUT :
  290. #ifdef WIN32
  291.                DialogBox(hInstance, "AboutBox", hMainWnd, AboutDlgProc);
  292. #else
  293.                DialogBox(hInstance, "AboutBox", hMainWnd, lpfnAboutDlgProc);
  294. #endif
  295.                return 0;
  296.  
  297.             case MSG_BREAK:
  298.               wilCancelBlocking();
  299.               wilCloseSocket(Socket);
  300.               break;
  301.  
  302.             case MSG_EXIT:
  303.               wilRelease();
  304.               DestroyWindow(hMainWnd);
  305.               break;
  306.  
  307.             case MSG_MAIL_PUT:
  308.               /* lets go do the email */
  309.               POST_MSG(SMTP_BEGIN);
  310.               break;
  311.            }
  312.          break;
  313.  
  314.     case WM_USER: /* posted by WIL */
  315.       AsyncProcessMsg(lParam);
  316.       break;
  317.  
  318.     case WM_USER+1:  /* posted by POST_MSG [defined in async.h] */
  319.       /* test response code */
  320.       if(lParam>=500)
  321.         {/* SMTP server returns fatal error code */
  322.          POST_MSG(SMTP_QUIT_FAILURE);
  323.          break;
  324.         }
  325.       /* execute case */
  326.       switch(wParam)
  327.         {
  328.          case SMTP_BEGIN:
  329.            AsyncSetEcho(TRUE);
  330.            SetCursor(WaitCursor);
  331.            /* connect to SMTP server */
  332.            Socket = AsyncConnect(hMainWnd,"SMTP",(LPSTR)SmtpString,
  333.                      SMTP_PORT, SMTP_CONN_SUCCESS,
  334.                      SMTP_QUIT_FAILURE, ASYNC_SINGLE_LINE);
  335.            break;
  336.  
  337.          case SMTP_CONN_SUCCESS:
  338.            /* send HELO (hello) command */
  339.            Ptr = StringChar((LPSTR)FromString,'@');
  340.            wsprintf((LPSTR)Temp,"HELO %s",(LPSTR)(Ptr+1));
  341.            AsyncCommand((LPSTR)Temp, SMTP_HELO_SUCCESS,
  342.                        SMTP_QUIT_FAILURE, ASYNC_SINGLE_CODED);
  343.            break;
  344.  
  345.          case SMTP_HELO_SUCCESS:
  346.            /* send MAIL FROM command */
  347.            wsprintf((LPSTR)Temp,"MAIL FROM:<%s>",(LPSTR)FromString);
  348.            AsyncCommand((LPSTR)Temp,SMTP_FROM_SUCCESS,
  349.                        SMTP_QUIT_FAILURE, ASYNC_SINGLE_CODED);
  350.            break;
  351.  
  352.          case SMTP_FROM_SUCCESS:
  353.            /* read next email destination address */
  354.            BufSize = ReadTextLine(RcptHandle, (LPSTR)InBuffer, MAX_BUF);
  355.            if(BufSize<=0)
  356.              {/* end of RCPT file */
  357.               _lclose(RcptHandle);
  358.               POST_MSG(SMTP_TO_SUCCESS);
  359.              }
  360.            /* strip trailing CR, LF from RCPT string */
  361.            StripCRLF((LPSTR)InBuffer);
  362.            /* do (minimal) email address validation */
  363.            Ptr = StringChar((LPSTR)Temp,'@');
  364.            if(Ptr==NULL)
  365.              {wsprintf((LPSTR)Temp,"Email address '%s' missing '@' (skipping)");
  366.               DisplayString((LPSTR)Temp);
  367.               POST_MSG(SMTP_FROM_SUCCESS);
  368.              }
  369.            /* send RCPT TO (receipt to) command */
  370.            wsprintf((LPSTR)Temp,"RCPT TO:<%s>",(LPSTR)InBuffer);
  371.            AsyncCommand((LPSTR)Temp, SMTP_FROM_SUCCESS,
  372.                        SMTP_QUIT_FAILURE, ASYNC_SINGLE_CODED);
  373.            break;
  374.  
  375.          case SMTP_TO_SUCCESS:
  376.            /* send DATA command */
  377.            AsyncCommand("DATA", SMTP_DATA_SUCCESS,
  378.                         SMTP_QUIT_FAILURE, ASYNC_SINGLE_CODED);
  379.            break;
  380.  
  381.          case SMTP_DATA_SUCCESS:
  382.            /* get next line from disk */
  383.            BufSize = ReadTextLine(MailHandle, (LPSTR)InBuffer, MAX_BUF);
  384.            if(BufSize<=0)
  385.              {/* end of file */
  386.               _lclose(MailHandle);
  387.               /* append line with only '.' */
  388.               wilWriteString(Socket,".\r\n");
  389.               DisplayLine("<EOF>");
  390.               POST_MSG(SMTP_QUIT_BEGIN);
  391.               break;
  392.              }
  393.            /* ready to send text line */
  394.            POST_MSG(SMTP_SEND);
  395.            break;
  396.  
  397.          case SMTP_SEND:
  398.            /* does buffer consist of lone '.' ? */
  399.            if((InBuffer[0]=='.')&&(InBuffer[1]=='\r')&&(InBuffer[2]=='\n'))
  400.              {/* "quote" the period */
  401.               InBuffer[1] = '.';
  402.               InBuffer[2] = '\r';
  403.               InBuffer[3] = '\n';
  404.               InBuffer[4] = '\0';
  405.               BufSize = 4;
  406.              }
  407.            /* send the buffer */
  408.            Code = wilWriteSocket(Socket,(LPSTR)InBuffer,BufSize);
  409.            if(Code<0)
  410.              {/* socket write error */
  411.               DisplayError(Code, "WriteSocket:");
  412.               POST_MSG(SMTP_QUIT_FAILURE);
  413.               break;
  414.              }
  415.            if(EchoFlag) WriteTheString((LPSTR)InBuffer,BufSize);
  416.            /* go get another buffer to write */
  417.            BufSize = 0;
  418.            POST_MSG(SMTP_DATA_SUCCESS);
  419.            break;
  420.  
  421.          case SMTP_QUIT_BEGIN:
  422.            AsyncSetEcho(TRUE);
  423.            /* send QUIT command */
  424.            AsyncCommand("QUIT", SMTP_QUIT_SUCCESS,
  425.                         SMTP_QUIT_FAILURE, ASYNC_SINGLE_CODED);
  426.            break;
  427.  
  428.          case SMTP_QUIT_FAILURE:
  429.            DisplayLine("SMTP command has failed...");
  430.            wilCloseSocket(Socket);
  431.            SetCursor(ArrowCursor);
  432.            break;
  433.            /* fall thru... */
  434.  
  435.          case SMTP_QUIT_SUCCESS:
  436.            /* all done */
  437.            DisplayLine("SMTP command succeeds.");
  438.            wilCloseSocket(Socket);
  439.            SetCursor(ArrowCursor);
  440.            break;
  441.         } /* end-switch(wParam) */
  442.  
  443.     case WM_PAINT:
  444.       HideCaret(hMainWnd);
  445.       hDC = BeginPaint(hMainWnd, &ps);
  446.       SetMapMode(hDC,MM_ANISOTROPIC);
  447.       SelectObject(hDC, GetStockObject(OEM_FIXED_FONT) );
  448.       PaintMain(hDC,&ps);
  449.       EndPaint(hMainWnd,&ps);
  450.       SetCaretPos(PaintGetColPos(),PaintGetRowPos());
  451.       ShowCaret(hMainWnd);
  452.       break;
  453.  
  454.     case WM_DESTROY:
  455.       PostQuitMessage(0);
  456.       break;
  457.  
  458.     default:
  459.       return (DefWindowProc(hMainWnd, iMsg, wParam, lParam));
  460.    }
  461.  return 0;
  462. } /* end MainWndProc */
  463.   
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.   
  575.